package com.library.admin.modules.menu.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.library.admin.modules.menu.entity.Menu;
import com.library.admin.modules.menu.vo.MenuVO;
import com.library.admin.modules.menu.bo.MenuPage;
import com.library.admin.modules.menu.bo.MenuInsert;
import com.library.admin.modules.menu.bo.MenuUpdate;
import com.library.admin.modules.menu.mapper.MenuMapper;
import com.library.admin.modules.menu.struct.MenuStructMapper;
import com.library.admin.modules.menu.service.MenuService;
import com.library.admin.modules.rolemenu.service.RoleMenuService;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import com.library.common.util.PageCovertUtil;

import java.util.*;
import java.util.stream.Collectors;


/**
 * @Author xyh
 * @Desc 后台管理菜单表(Menu)表服务实现类
 * @Date 2023-10-02 15:09:35
 */

@Log4j2
@Service("menuService")
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    @Resource
    private MenuStructMapper menuStructMapper;
    @Resource
    private MenuMapper menuMapper;
    @Resource
    private RoleMenuService roleMenuService;
    /**
     * key：menuId
     * value：Menu
     */
    Map<Integer, Menu> menuMap = new HashMap<>();


    @Override
    public IPage<MenuVO> queryByPage(MenuPage page) {
        // 查询条件
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        // 查询分页数据
        Page<Menu> menuPage = new Page<Menu>(page.getCurrent(), page.getSize());
        IPage<Menu> pageData = baseMapper.selectPage(menuPage, queryWrapper);

        //转换成vo
        IPage<MenuVO> records = PageCovertUtil.pageVoCovert(pageData, MenuVO.class);
        return records;
    }

    @Override
    public void init() {
        List<Menu> menuList = menuMapper.selectList(new QueryWrapper<>());
        if(CollUtil.isNotEmpty(menuList)) {
            for (Menu menu : menuList) {
                menuMap.put(menu.getId(), menu);
            }
            log.info("用户添加缓存完成！");
        }
    }


    @Override
    public MenuVO queryById(Integer id) {
        Menu menu = menuMap.get(id);
        if (menu == null) {
            menu = baseMapper.selectById(id);
        }
        MenuVO vo = new MenuVO(menu);
        return vo;
    }

    @Override
    public boolean insert(MenuInsert menuInsert) {
        Menu menu = menuStructMapper.insertToMenu(menuInsert);
        save(menu);
        menuMap.put(menu.getId(), menu);
        return true;
    }


    @Override
    public boolean update(MenuUpdate menuUpdate) {
        Menu menu = menuStructMapper.updateToMenu(menuUpdate);
        updateById(menu);
        menuMap.put(menu.getId(), menu);
        return true;
    }

    @Override
    public boolean deleteById(Integer id) {
        boolean b = removeById(id);
        menuMap.remove(id);
        return b;
    }

    @Override
    public List<MenuVO> getTreeMenu(Collection<Integer> roleIds) {
        //当前角色关联的菜单id
        Set<Integer> menuIds = new HashSet<>();
        List<Menu> menuList = new ArrayList<>();
        if (CollUtil.isEmpty(roleIds)) {
            menuList = menuMap.values().stream().collect(Collectors.toList());
        } else {
            //获取当前用户的菜单id
            menuIds = roleMenuService.getMenuIdsByRoleIds(roleIds);
            //角色关联的菜单，可能没有父级菜单，这里需要补父级菜单否则左侧菜单栏不会展示
            menuList = this.traceParentMenu(menuIds);
        }

        //获取菜单树
        menuList.removeAll(Collections.singleton(null));
        List<MenuVO> voList = menuTree(menuList);
        //对子菜单排序
        if (CollUtil.isNotEmpty(voList)) {
            voList.forEach(m -> {
                if (CollUtil.isNotEmpty(m.getChildren())) {
                    Collections.sort(m.getChildren(), Comparator.comparing(MenuVO::getOrderNo));
                }
            });
            //对父菜单排序
            Collections.sort(voList, Comparator.comparing(MenuVO::getOrderNo));
        }
        return voList;
    }

    /**
     * 补足父菜单
     * @param menuIds
     * @return
     */
    private List<Menu> traceParentMenu(Collection<Integer> menuIds) {
        Set<Integer> ret = new HashSet<>(menuIds.size() << 1);
        ret.addAll(menuIds);
        //当前循环
        HashSet<Integer> thisMenuIds = new HashSet();
        thisMenuIds.addAll(menuIds);
        //下次循环
        HashSet<Integer> nextMenuLoop = new HashSet<>(menuIds);
        //返回菜单信息
        List<Menu> list = new ArrayList<>();
        for (int i = 0; i < thisMenuIds.size(); i++) {
            for (Integer menuId : thisMenuIds) {
                Menu menu = menuMap.get(menuId);
                //只查找子菜单，增删改查接口的菜单不进行展示
                if (menu != null && menu.getHideMenu() == 0) {
                    Integer parentId = menu.getParentId();
                    if (Objects.nonNull(parentId)) {
                        //上级菜单可能还会有父级菜单，继续执行
                        nextMenuLoop.add(parentId);
                    }
                }
            }
            ret.addAll(nextMenuLoop);
            //更新当前循环集合
            thisMenuIds.clear();
            thisMenuIds.addAll(nextMenuLoop);
            nextMenuLoop.clear();
        }
        if (CollUtil.isNotEmpty(ret)) {
            for (Integer m : ret) {
                list.add(menuMap.get(m));
            }
        }
        return list;
    }

    /**
     * 获取菜单树
     *
     * @param menuList
     * @return
     */
    private List<MenuVO> menuTree(List<Menu> menuList) {
        List<MenuVO> parents = new ArrayList<>();
        //循环查出的menuList，找到根节点（最大的父节点）的子节点
        for (Menu menu : menuList) {
            if (menu.getParentId().equals(0)) {
                MenuVO vo = new MenuVO(menu);
                parents.add(vo);
            }
        }
        for (MenuVO parent : parents) {
            childMenuNode(parent, menuList);
        }
        return parents;
    }

    /**
     * 获取子菜单
     *
     * @param parent
     * @param menuList
     */
    private void childMenuNode(MenuVO parent, List<Menu> menuList) {
        for (Menu menu : menuList) {
            //如果子节点的pid等于父节点的ID，则说明是父子关系
            if (menu.getParentId().equals(parent.getId())) {
                MenuVO child = new MenuVO(menu);
                // 是父子关系，则将其放入子Children里面
                parent.getChildren().add(child);
                // 继续调用递归算法，将当前作为父节点，继续找他的子节点，反复执行。
                childMenuNode(child, menuList);
            }
        }
    }

}
